package com.linxchong.security.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.net.http.HttpRequest;

/**
 * @Author:linchong
 * @CreateTime:2020-07-15 10:09
 * @Description:授权的过滤器
 */
@Slf4j
@Component
public class AuthorizationFilter extends ZuulFilter {
	@Override
	public String filterType() {
		return "pre";
	}

	@Override
	public int filterOrder() {
		return 3;
	}

	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 授权逻辑：
	 *      1.判断当前请求是否需要身份认证/权限判断（根据当前请求）【查数据库或其他判断路径是否需要认证】
	 *      2.如果需要认证，获取TokenInfo,
	 *          判断值(是否为空、是否可用)
	 *              失败：做对应的处理,更新审计日志
	 *              成功：判断是否有权限，根据令牌中的信息
	 * @return
	 * @throws ZuulException
	 */
	@Override
	public Object run() throws ZuulException {
		//开始授权...
		log.info("authorization start...");
		RequestContext requestContext = RequestContext.getCurrentContext();
		HttpServletRequest request = requestContext.getRequest();
		if(isNeedAuth(request)){
			TokenInfo tokenInfo = (TokenInfo) request.getAttribute("tokenInfo");
			log.info("token info:{}",tokenInfo);
			if(tokenInfo != null && tokenInfo.isActive()){
				//认证通过，没有权限，更新审计日志,网关实现权限校验
				if(!hasPermission(tokenInfo,request)){
					log.info("audit log update fail 401");
					handleError(403,requestContext);
				}
				//添加自定义的用户信息到head
				requestContext.addZuulRequestHeader("username",tokenInfo.getUser_name());
			}else{
				//非/token开头的
				if(!StringUtils.startsWith(request.getRequestURI(),"/token")){
					//认证失败，更新审计日志
					log.info("audit log update fail 401");
					handleError(401,requestContext);
				}
			}
		}
		return null;
	}

	/**
	 * 根据用户信息和请求去判断当前用户是否有权限去访问服务
	 * @param tokenInfo
	 * @param request
	 * @return
	 */
	private boolean hasPermission(TokenInfo tokenInfo, HttpServletRequest request) {
		boolean flag = RandomUtils.nextInt() %2 == 0;
		log.info("result is {}",flag);
		return true;
	}

	/**
	 * 处理错误信息的放回
	 * @param status 响应状态码
	 * @param requestContext
	 */
	private void handleError(int status, RequestContext requestContext) {
		requestContext.getResponse().setContentType("application/json");
		requestContext.setResponseStatusCode(status);

		requestContext.setResponseBody("{\"code\":"+status+",\"message\":\"auth fail\"}");
		//设置请求不向下走
		requestContext.setSendZuulResponse(false);
	}

	private boolean isNeedAuth(HttpServletRequest request) {
		return true;
	}
}
















